package io.itit.ecp.admin.provide.action.controller;


import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.common.enums.MeterDeviceStaticsTypeEnums;
import io.itit.ecp.admin.provide.action.req.PracticalAnalysisQueryReq;
import io.itit.ecp.admin.provide.action.resp.EmissionReductionDataResp;
import io.itit.ecp.admin.provide.action.resp.PracticalAnalysisResp;
import io.itit.ecp.admin.server.entity.CarbonNeutralityPlanDataEntity;
import io.itit.ecp.admin.server.entity.EnergyDataEntity;
import io.itit.ecp.admin.server.entity.MeterDeviceEntity;
import io.itit.ecp.admin.server.entity.SceneProjectEntity;
import io.itit.ecp.admin.server.entity.extend.EnergyDataExtEntity;
import io.itit.ecp.admin.server.service.ICarbonNeutralityPlanDataService;
import io.itit.ecp.admin.server.service.ICarbonSinkDataService;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.IExport;
import io.itit.grass.common.provide.action.validation.IQueryPage;
import io.itit.grass.common.provide.action.validation.IRequired;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Objects;

@Api(tags = "规实分析")
@RestController
@RequestMapping("/ecp-admin/practicalAnalysis")
public class PracticalAnalysisController {

    @Resource
    private ICarbonNeutralityPlanDataService carbonNeutralityPlanDataService;

    @Resource
    private ICarbonSinkDataService carbonSinkDataService;


    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:practicalAnalysis:search")
    public ResultResp<IPage<PracticalAnalysisResp>> queryPage(@RequestBody @Validated(IQueryPage.class) PracticalAnalysisQueryReq req) {
        Page<PracticalAnalysisResp> page = buildQW(req).joinPage(PageUtils.getPage(req, PracticalAnalysisResp.class), PracticalAnalysisResp.class);
        for (PracticalAnalysisResp item : page.getRecords()) {
            item.setActualCarbonEmissions(ObjectUtil.defaultIfNull(queryCarbonEmissionData(item.getSceneProjectId(), item.getSolidifyDate(), item.getSolidifyDate()), BigDecimal.ZERO));
            item.setActualCarbonSequestration(carbonSinkDataService.computeCarbonReductionTotal(item.getSceneProjectId(),
                    item.getSolidifyDate().atTime(LocalTime.MIN), item.getSolidifyDate().atTime(LocalTime.MAX)));
            item.setActualCarbonZero(getEmissionReductionData(item.getSceneProjectId(), item.getSolidifyDate().atStartOfDay(), item.getSolidifyDate().atTime(LocalTime.MAX)));
            item.setActualCarbonNeutrality(item.getActualCarbonEmissions()
                    .subtract(getActualCarbonNeutrality(item.getSceneProjectId(), item.getSolidifyDate().atStartOfDay(), item.getSolidifyDate().atTime(LocalTime.MAX))));
        }
        return ResultResp.success(page);
    }

    // 实际碳中和, 碳排放量-（光伏上网部分零碳量+碳汇量)
    private BigDecimal getActualCarbonNeutrality(String sceneProjectId, LocalDateTime startDate, LocalDateTime endDate) {
        // 光伏上网
        BigDecimal value = ObjectUtil.defaultIfNull(Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("SUM(meter_value)", "meterValue", false))
                .eq(EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .eq(EnergyDataEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.readMeterType13.getValue())
                .eq(EnergyDataEntity::getStaticsType, MeterDeviceStaticsTypeEnums.ON_GRID_ENERGY.getValue())
                .ge(Objects.nonNull(startDate), EnergyDataEntity::getSolidifyDate, startDate)
                .le(EnergyDataEntity::getSolidifyDate, endDate)
                .joinGetOne(BigDecimal.class), BigDecimal.ZERO);
        //碳汇量
        BigDecimal carbonSinkValue = carbonSinkDataService.computeCarbonReductionTotal(sceneProjectId, null, null, startDate, endDate);
        return value.add(carbonSinkValue);
    }

    private BigDecimal getEmissionReductionData(String sceneProjectId, LocalDateTime startDate, LocalDateTime endDate) {
        BigDecimal value = Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder.add("SUM(ecp_tt_energy_data.carbon_emission)", "carbonEmission", false))
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .selectAs(t -> t.addFunAlias(MeterDeviceEntity::getDeviceCode, EnergyDataExtEntity::getDeviceCode)
                        .addFunAlias(MeterDeviceEntity::getDeviceName, EnergyDataExtEntity::getDeviceName)
                        .addFunAlias(MeterDeviceEntity::getReadMeterType, EnergyDataExtEntity::getReadMeterType)
                        .addFunAlias(MeterDeviceEntity::getReadMeterTag, EnergyDataExtEntity::getReadMeterTag)
                        .addFunAlias(MeterDeviceEntity::getProductTypeId, EmissionReductionDataResp::getProductTypeId)
                )
                .in(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .ge(Objects.nonNull(startDate), EnergyDataEntity::getSolidifyDate, startDate)
                .le(Objects.nonNull(endDate), EnergyDataEntity::getSolidifyDate, endDate).joinGetOne(BigDecimal.class);
        return ObjectUtil.defaultIfNull(value, BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
    }


    private BigDecimal queryCarbonEmissionData(String sceneProjectId, LocalDate start, LocalDate end) {
        LocalDateTime startTime = start.atTime(LocalTime.MIN);
        LocalDateTime endTime = end.atTime(LocalTime.MAX);
        return Joins.of(EnergyDataEntity.class)
                .selectAs(builder -> builder
                        .add("SUM(carbon_emission)", "carbonEmission", false))
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .notIn(MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(EnergyDataEntity::getSceneProjectId, sceneProjectId)
                .ge(EnergyDataEntity::getSolidifyDate, startTime)
                .le(EnergyDataEntity::getSolidifyDate, endTime)
                .joinGetOne(BigDecimal.class);
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:practicalAnalysis:deleteById")
    @Transactional
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        boolean result = carbonNeutralityPlanDataService.removeById(req.getId());
        return ResultResp.success(result);
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:practicalAnalysis:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        carbonNeutralityPlanDataService.removeBatchByIds(req.getIds(), 500);
        return ResultResp.success(true);
    }

    @ApiOperation("批量删除")
    @PostMapping("export")
    @RequiresPermissions("ecp-admin:practicalAnalysis:export")
    public void export(@RequestBody @Validated(IExport.class) PracticalAnalysisQueryReq req, HttpServletResponse response) {
        ExcelXSSFUtil.export("PracticalAnalysisExport", JsonUtil.toJson(buildQW(req).joinList(PracticalAnalysisResp.class)), response);
    }

    private static JoinLambdaWrapper<CarbonNeutralityPlanDataEntity> buildQW(PracticalAnalysisQueryReq req) {
        return Joins.of(CarbonNeutralityPlanDataEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, CarbonNeutralityPlanDataEntity::getSceneProjectId)
                .selectAs(SceneProjectEntity::getProjectName, PracticalAnalysisResp::getProjectName)
                .end()
                .eq(StringUtils.isNotEmpty(req.getSceneProjectId()), CarbonNeutralityPlanDataEntity::getSceneProjectId, req.getSceneProjectId())
                .ge(Objects.nonNull(req.getEffectiveTimeStart()), CarbonNeutralityPlanDataEntity::getSolidifyDate, req.getEffectiveTimeStart())
                .le(Objects.nonNull(req.getEffectiveTimeEnd()), CarbonNeutralityPlanDataEntity::getSolidifyDate, req.getEffectiveTimeEnd())
                .orderByDesc(CarbonNeutralityPlanDataEntity::getSolidifyDate)
                .last(StringUtils.isNotEmpty(req.getSortColumn()), PageUtils.lastOrderBy(req));
    }
}
